import paho.mqtt.client as mqtt
import json
import logging
from thickcharts.models import Mdata, Device
from thickcharts.utils import Wave, thick_cal
from thickness_api.settings import client_id, mqtt_broker, mqtt_port, username, password

# 接收到的mdata的回调函数
def mdata_cb(client, userdata, msg):
    payload = msg.payload
    save_mdata(payload)

# 接收到消息指令的回调函数
def msg_cb(client, userdata, msg):
    pass

# debug 模式下保存波形数据
def save_wave(payload):
    payload = eval(payload.decode())
    try:
        probe = payload['probe']
        device = Device.objects.get(probe=probe)
        wave_str = json.dumps(payload['wave_data'])
        device.wave = wave_str
        device.save()
        # print需要更改为日志记录
        print("保存wave数据成功！")
    except:
        print("保存wave数据失败！")

# 接收到波形数据时的回调函数
def wave_cb(client, userdata, msg):
    topic = msg.topic
    payload = msg.payload
    save_wave(payload)




# 接收到订阅消息时的回调函数
def on_message(client, userdata, msg):
    # print("p 4")
    pass
    # 可将信息写入到日志中
    # print(msg.topic + ':' + str(msg.payload))

# 连接数据接收时的回调函数
def on_connect(client, userdata, flags, rc):
    msg = '连接失败，位置错误'
    msgs = ['连接成功!', '连接拒绝，协议版本错误', '连接错误，客户端标识符无效', '连接错误，服务器不可用', '连接错误，用户名或密码错误', '连接错误,未授权6-255：当前未使用']
    if rc in range(6):
        msg = msgs[rc]
    print("connect with result code " + str(rc) + ' ' + msg)

# 将payload中的mdata数据保存到mdata model中
def save_mdata(client_id, thickness, temperature):
    try:
        new_mdata = Mdata()
        new_mdata.probe = Device.objects.filter(client_id=client_id).first().probe
        new_mdata.thickness = float(thickness)
        new_mdata.temperature = float(temperature)
        new_mdata.save()
        print("mdata保存成功！")
    except:
        print("mdata保存失败！")


# test主题的回调函数
def test_cb(client, userdata, msg):
    payload = msg.payload.decode()
    # payload = eval(msg.payload.decode())
    payload_json = json.loads(payload)
    state = payload_json["state"]
    # 表示下位机处于传输波形数据的模式
    if state == "2":
        client_id = payload_json["client_id"]
        wave = Wave(payload_json["data"])
        wave_list = wave.data_list
        devices = Device.objects.filter(client_id=client_id)
        if devices.count():
            device = devices.first()
            device.wave = json.dumps(wave_list)
            device.save()
        else:
            print("未找到对应的探头")
    # state=1表示下位机需要下发参数
    elif state == "1":
        client_id = payload_json["client_id"]
        devices = Device.objects.filter(client_id=client_id)
        if devices.count():
            device = devices.first()
            client_id = device.client_id
            start = device.start
            width = device.width
            scan_range = device.scan_range
            gain = device.gain
            client = new_client()
            payload = {
                "client_id": client_id,
                "flag": 0,
                "debug": "on",
                "scan_range": int(scan_range),
                "gain": int(gain),
                "strobe_start": int(start),
                "strobe_range": int(width),
            }
            client.publish('test/abc/down', json.dumps(payload))
            client.disconnect()
            print("{}初始化参数成功！".format(client_id))
        else:
            print("参数初始化失败")
    # flag=0表示下位机处于正常传输数据的模式
    elif state == "0":
        client_id = payload_json["client_id"]
        cal_time = payload_json["cal_time"]
        measure_time = payload_json["measure_time"]
        temperature = payload_json["temperature"]
        devices = Device.objects.filter(client_id=client_id)
        if devices.count():
            # print("cal_time:{},measure_time:{}".format(cal_time, measure_time))
            thickness = thick_cal(cal_time, measure_time, 1, 26)
            # print({"thickness: {}".format(thickness)})
            client_id = devices.first().client_id
            save_mdata(client_id, thickness, temperature)
            print("保存壁厚数据成功！")
        else:
            print("未找到对应的探头")

# 初始化paho-mqtt相关服务
def mqtt_init():
    # 日志信息配置
    logging.basicConfig(filename='./iotlog.log', level=logging.DEBUG, format='%(asctime)s [%(name)s:%(lineno)d] [%(levelname)s]- %(message)s')

    client = mqtt.Client(client_id=client_id, clean_session=False, userdata=None, protocol=mqtt.MQTTv311, transport='tcp', reconnect_on_failure=True)
    client.enable_logger()
    # 需要用户名和密码的情况
    client.username_pw_set(username=username, password=password)
    client.on_connect = on_connect
    client.on_message = on_message

    # 连接mosquito服务器，必须在订阅之前连接
    client.connect(host=mqtt_broker, port=mqtt_port, keepalive=60)

    # 自动重连设置
    client.reconnect_delay_set(min_delay=1, max_delay=120)

    # 设置断开连接后的遗嘱信息
    will_msg = {
        "msg": "paho-mqtt offline"
    }
    client.will_set("thick/data/msg/", payload=json.dumps(will_msg))

    # 订阅thick相关主题，并对不同topic接收到数据后绑定回调函数
    client.subscribe('thick/#')
    client.message_callback_add('thick/data/mdata/#', mdata_cb)
    client.message_callback_add('thick/data/msg/#', msg_cb)
    client.message_callback_add('thick/data/wave/#', wave_cb)

    # test
    client.subscribe('test/#')
    client.message_callback_add('test/abc/up', test_cb)

    print("loop start")
    # 非阻塞式自动处理收发数据。
    client.loop_start()
    # 阻塞式自动处理收发数据，断开会自动重连
    # client.loop_forever()

# 暂时不起作用，需要调试
def mqtt_disconnect():
    client = mqtt.Client(client_id=client_id)
    print("paho-mqtt断开连接")
    client.loop_stop()
    client.disconnect()

# 开启波形数据的debug模式
def debug_on(device):
    probe = device.probe
    client_id = device.client_id
    client = new_client()
    # client = mqtt.Client(client_id='', clean_session=True, userdata=None, protocol=mqtt.MQTTv311,
    #                      transport='tcp', reconnect_on_failure=True)
    #
    # client.username_pw_set(username=username, password=password)
    # # 连接mosquitto服务器，必须在订阅之前连接
    # client.connect(host=mqtt_broker, port=mqtt_port, keepalive=60)
    # state = 2 控制下位机打开debug 模式,传输波形数据和参数
    payload = {
        "client_id": client_id,
        "flag": 2,
        "probe": probe,
        "debug": "on",
        "scan_range": 0,
        "gain": 0,
        "strobe_start": 0,
        "strobe_range": 0
    }
    payload = json.dumps(payload)
    # 设备端需要订阅下面的主题
    # 给设备端发送消息，通知其开启debug模式
    # client.publish('thick/control/debugon/deviceId', payload=payload)
    # test
    # client.publish('test/abc/down', payload=payload)
    topic = "thick/down/" + client_id
    client.publish(topic, payload=payload)
    # 需要更改为日志模式
    print("{}开启debug 模式".format(client_id))
    client.disconnect()

# 关闭debug模式
def debug_off(device):
    client_id = device.client_id
    client = new_client()
    payload = {
        "client_id": client_id,
        "flag": 0,
        "debug": "off",
        "scan_range": 0,
        "gain": 0,
        "strobe_start": 0,
        "strobe_range": 0
    }
    payload = json.dumps(payload)
    # 设备端需要订阅下面的主题
    # 给设备端发送消息，通知其关闭debug模式
    # client.publish('thick/control/debugoff/deviceId', payload=payload)
    client.publish('test/abc/down', payload=payload)
    # 需要更改为日志模式
    print("{}关闭debug 模式".format(client_id))
    client.disconnect()

def new_client(id=None):
    # 日志信息配置
    logging.basicConfig(filename='./iotlog.log', level=logging.DEBUG,
                        format='%(asctime)s [%(name)s:%(lineno)d] [%(levelname)s]- %(message)s')

    if id:
        client = mqtt.Client(client_id=id, clean_session=True, userdata=None, protocol=mqtt.MQTTv311,
                         transport='tcp', reconnect_on_failure=True)
    else:
        client = mqtt.Client(clean_session=True, userdata=None, protocol=mqtt.MQTTv311,
                             transport='tcp', reconnect_on_failure=True)
    client.enable_logger()
    # 需要用户名和密码的情况
    client.username_pw_set(username=username, password=password)
    client.on_connect = on_connect
    client.on_message = on_message

    # 连接mosquito服务器，必须在订阅之前连接
    client.connect(host=mqtt_broker, port=mqtt_port, keepalive=60)
    return client
















